"""
05_llm_integration.py - LLM Integration with LangChain
========================================================
Chapter 7: Connecting your graph to real language models.

KEY CONCEPTS:
  ★ ChatOpenAI / ChatAnthropic - LLM providers
  ★ MessagesState - Built-in state for chat
  ★ SystemMessage / HumanMessage - Message types
  ★ Mock LLM - For testing without API keys

Run: python src/05_llm_integration.py
"""
import os, sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Annotated
from operator import add

class ChatState(TypedDict):
    messages: Annotated[list, add]
    response: str

def chatbot_node(state: ChatState) -> dict:
    last_msg = state["messages"][-1] if state["messages"] else "Hello"
    content = last_msg if isinstance(last_msg, str) else str(last_msg)
    try:
        from src.utils.llm_config import get_llm
        llm = get_llm()
        from langchain_core.messages import HumanMessage
        result = llm.invoke([HumanMessage(content=content)])
        response = result.content
    except Exception:
        response = f"[Echo] You said: {content}"
    return {"messages": [f"Assistant: {response[:200]}"], "response": response[:200]}

graph = StateGraph(ChatState)
graph.add_node("chatbot", chatbot_node)
graph.add_edge(START, "chatbot")
graph.add_edge("chatbot", END)
app = graph.compile()

if __name__ == "__main__":
    print("=" * 60)
    print("05: LLM Integration")
    print("=" * 60)
    result = app.invoke({"messages": ["What is LangGraph in one sentence?"]})
    print(f"\n  Response: {result['response']}")
    print(f"\n{'=' * 60}\n✅ LLM integration complete!")
